﻿#pragma once
#include "Common.h"
#include "ObjectPool.h"
#include "PageMap.h"

// page cache底层也是spanlist 哈希桶  但是映射规则不同  按span页数进行映射  如 1号桶挂大小1个页的span 2号桶挂大小2个页的span  并且单个span内部不切分
// 为了保证全局只有唯⼀的page cache，这个类被设计成了单例模式
// pagecache 作为整个高并发内存池的第三层 在整个运作逻辑里 有效减少了向系统申请资源的次数 很大程度的提高了性能
// 申请 central问pagecache要span  对应桶里有就给 没有 去大一点的桶里看看有没有大的span 然后切出来一块对应大小的span 剩下的挂到对应的桶上 最大的桶里也没有 问系统要
// 释放 central把span还回来 pagecache 放回对应位置  同时 执行合并 把小span合成大span
// 同centralcache 需要加锁 但是  不能加桶锁了  在申请释放的时候涉及多个桶的操作  这时候直接上一把大锁 都给锁起来
// 同时 为了方便span的合并 记录首位页号和span的映射关系
// 用定长内存池的new/delete替换整个过程中的new/delete 
// 用基数树来替代unordered_map 缓解锁竞争  优化数据量过多时的查询效率 提高性能 
class PageCache
{
public:
	static PageCache* GetInstance()
	{
		return &_sInst;
	}

	// 获取从对象到span的映射
	Span* MapObjectToSpan(void* obj);

	// 释放空闲span回到Pagecache，并合并相邻的span
	void ReleaseSpanToPageCache(Span* span);

	// 获取⼀个K⻚的span
	Span* NewSpan(size_t k);
	std::mutex _pageMtx;
	
private:
	PageCache() {}
	PageCache(const PageCache&) = delete;
	static PageCache _sInst;
private:
	SpanList _spanlist[NP];
	ObjectPool<Span> _spanPool;
	//std::unordered_map<PAGE_ID, Span*> _idSpanMap;
	TCMalloc_PageMap1<32 - PAGE_SHIFT> _idSpanMap; 
};